/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "console.hpp"
#include "logger.hpp"
#include "service/message_loop.hpp"
#include "service/service.hpp"

#include <bamp/basic_message.hpp>
#include <bamp/message_ptr.hpp>

#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

#include <memory>
#include <sstream>


namespace pt = boost::property_tree;


struct bamp::Console::Implementation
{
    Implementation(bamp::Service& svc)
        : m_svc(svc) {}

    // Console messaging API
    void command(MessagePtr msg);
    void exit(MessagePtr msg);

    // Parent service object
    bamp::Service&    m_svc;
};


bamp::Console::Console()
    : pimpl(new Implementation(*this))
{
    // Connect console message handlers
    thread()->connect
        ("bamp::command", &bamp::Console::Implementation::command, *pimpl);
    thread()->connect
        ("bamp::exit", &bamp::Console::Implementation::exit, *pimpl);
}

bamp::Console::~Console()
{

}

void bamp::Console::Implementation::command(MessagePtr msg)
{
    // Read the command into a stream
    std::string cmd = msg.getArgByName("cmd");
    std::istringstream is(cmd);

    // Parse the string received. It should be XML.
    pt::ptree tree;
    try {
        read_xml(is, tree);
    } catch (const std::exception& e) {
        BAMP_LOG_ERROR(e.what());
        return;
    }

    // Check the parsed string for commands
    BOOST_FOREACH(pt::ptree::value_type& cmd, tree)
    {
        BasicMessage outMsg(cmd.first);

        // Check the command for arguments
        BOOST_FOREACH(pt::ptree::value_type& arg, cmd.second)
        {
            std::string name = arg.first;
            std::string type;
            std::string value;
            if (arg.second.count("type"))
                type = arg.second.get<std::string>("type");
            if (arg.second.count("value"))
                value = arg.second.get<std::string>("value");
            outMsg.setArg(name, Value(type, value));
        }

        // Send the message
        m_svc.target()->send(outMsg);
    }
}

void bamp::Console::Implementation::exit(MessagePtr msg)
{
    m_svc.stop();
    BAMP_LOG_TRACE("console subsystem stopping");
}
